package com.ruoyi.core.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import com.ruoyi.core.exception.RunException;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author wanghao 913351190@qq.com
 * @create 2021/6/24 14:14
 */
public abstract class JsonUtil {

    /**
     * 默认日期时间格式
     */
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    /**
     * 默认日期格式
     */
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    /**
     * 默认时间格式
     */
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
    /**
     * 默认时间戳时间格式
     */
    public static final String DEFAULT_TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
    private static final ObjectMapper objectMapper = new ObjectMapper();

    static {
        //对象的所有字段全部列入
        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        //取消默认转换timestamps形式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //忽略空Bean转json的错误
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        //所有的日期格式都统一为以下的样式，即yyyy-MM-dd HH:mm:ss
        objectMapper.setDateFormat(new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT));
        //忽略 在json字符串中存在，但是在java对象中不存在对应属性的情况。防止错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

//        objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); //忽略大小写
//        objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); //根据字段值序列化
//        objectMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE); //忽略Get方法读取值

        /*注册模块*/
        objectMapper
                // Java8的时间兼容模块
                .registerModule(javaTimeModule())
                // Jdk8Module() -> 注册jdk8模块
                .registerModule(new Jdk8Module())
                // new ParameterNamesModule() ->
                .registerModule(new ParameterNamesModule());
    }

    private JsonUtil() {
    }

    /**
     * 序列化java.time对象
     *
     * @return
     */
    public static JavaTimeModule javaTimeModule() {

        JavaTimeModule javaTimeModule = new JavaTimeModule();

        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
        javaTimeModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
        javaTimeModule.addSerializer(Long.class, ToStringSerializer.instance);

        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));


        //Date
        javaTimeModule.addSerializer(Date.class, new JsonSerializer<Date>() {
            @Override
            public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) {
                try {
                    SimpleDateFormat formatter = new SimpleDateFormat(JsonUtil.DEFAULT_DATE_TIME_FORMAT);
                    String formattedDate = formatter.format(date);
                    jsonGenerator.writeString(formattedDate);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        javaTimeModule.addDeserializer(Date.class, new JsonDeserializer<Date>() {
            @Override
            public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
                try {
                    SimpleDateFormat format = new SimpleDateFormat(JsonUtil.DEFAULT_DATE_TIME_FORMAT);
                    String date = jsonParser.getText();
                    return format.parse(date);
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        });

        //Timestamp
        javaTimeModule.addSerializer(Timestamp.class, new JsonSerializer<Timestamp>() {
            @Override
            public void serialize(Timestamp date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) {
                try {
                    SimpleDateFormat formatter = new SimpleDateFormat(JsonUtil.DEFAULT_TIMESTAMP_FORMAT);
                    String formattedDate = formatter.format(date);
                    jsonGenerator.writeString(formattedDate);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        javaTimeModule.addDeserializer(Timestamp.class, new JsonDeserializer<Timestamp>() {
            @Override
            public Timestamp deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
                try {
                    SimpleDateFormat format = new SimpleDateFormat(JsonUtil.DEFAULT_TIMESTAMP_FORMAT);
                    String date = jsonParser.getText();
                    Date parse = format.parse(date);
                    return new Timestamp(parse.getTime());
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        });

//        //CLOB
//        javaTimeModule.addSerializer(CLOB.class, new JsonSerializer<CLOB>() {
//            @Override
//            public void serialize(CLOB clob, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) {
//                try {
//                    if (clob == null || clob.isNull()) {
//                        jsonGenerator.writeString((String) null);
//                    } else {
//                        jsonGenerator.writeString(clob.stringValue());
//                    }
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//            }
//        });
//
//        //BLOB
//        javaTimeModule.addSerializer(BLOB.class, new JsonSerializer<BLOB>() {
//            @Override
//            public void serialize(BLOB blob, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) {
//                try {
//                    if (blob == null || blob.isNull()) {
//                        jsonGenerator.writeString((String) null);
//                    } else {
//                        try (InputStream inputStream = blob.getBinaryStream()) {
//                            try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
//                                byte[] buffer = new byte[1024];
//                                int len;
//                                while ((len = inputStream.read(buffer)) > 0) {
//                                    outputStream.write(buffer, 0, len);
//                                }
//                                byte[] bytes = outputStream.toByteArray();
//                                String base64 = Base64.getEncoder().encodeToString(bytes);
//                                jsonGenerator.writeString(base64);
//                            }
//                        }
//                    }
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }
//            }
//        });


        return javaTimeModule;
    }

    public static ObjectMapper getObjectMapper() {
        return objectMapper;
    }

    /**
     * 序列化
     *
     * @param value
     * @return
     */
    public static String toJson(Object value) {
        try {
            if (value == null) {
                return null;
            }
            if (value instanceof String) {
                return (String) value;
            }
            return objectMapper.writeValueAsString(value);
        } catch (Exception e) {
            throw new RunException(e.getMessage(), e);
        }
    }

    /**
     * 反序列化
     *
     * @param str
     * @param valueType
     * @param <T>
     * @return
     */
    public static <T> T toBean(Object str, Class<T> valueType) {
        try {
            if (str == null) {
                return null;
            }
            if (str instanceof String) {
                return objectMapper.readValue((String) str, valueType);
            }
            if (valueType.isAssignableFrom(str.getClass())) {
                return (T) str;
            }
            return objectMapper.readValue(toJson(str), valueType);
        } catch (Exception e) {
            throw new RunException(e.getMessage(), e);
        }
    }

    /**
     * 反序列化
     *
     * @param str
     * @param valueType
     * @param <T>
     * @return
     */
    public static <T> List<T> toBeans(Object str, Class<T> valueType) {
        try {
            if (str == null) {
                return new ArrayList<>();
            }
            if (str instanceof String) {
                return objectMapper.readerForListOf(valueType).readValue((String) str);
            }
            return objectMapper.readerForListOf(valueType).readValue(toJson(str));
        } catch (Exception e) {
            throw new RunException(e.getMessage(), e);
        }
    }

    public static JsonNode toJsonNode(Object str) {
        return toBean(str, JsonNode.class);
    }

    public static Map toMap(Object str) {
        return toBean(str, Map.class);
    }

}